package com.main.tripplanner.algorithms.impl;

import java.util.ArrayList;
import java.util.List;

import net.sf.javailp.Linear;
import net.sf.javailp.OptType;
import net.sf.javailp.Problem;
import net.sf.javailp.Result;
import net.sf.javailp.Solver;
import net.sf.javailp.SolverFactory;
import net.sf.javailp.SolverFactoryLpSolve;
import net.sf.javailp.VarType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.main.tripplanner.algorithms.CityAttractionsOpt;
import com.main.tripplanner.persistent.Attraction;
import com.main.tripplanner.persistent.Attraction.AttractionType;
import com.main.tripplanner.persistent.City;
import com.main.tripplanner.persistent.Dosage;
import com.main.tripplanner.service.AttractionService;

@Service
public class CityAttractionsOptImpl implements CityAttractionsOpt{

	@Autowired
	private AttractionService attractionService;

	public List<Attraction>  getOptimalCityAttractions( City city, Attraction bestAttraction, Dosage desiredDosage){
		List<Attraction> resultAttractions = new ArrayList<Attraction>();
		List<Attraction> cityAttractions = attractionService.getCityAttractions(city, bestAttraction);
		SolverFactory factory = new SolverFactoryLpSolve(); // use lp_solve
		factory.setParameter(Solver.VERBOSE, 0); 
		factory.setParameter(Solver.TIMEOUT, 100); // set timeout to 100 seconds
		Problem problem = new Problem();
		//Set attraction boolean variables (to choose or not)
		Linear linearObjective = new Linear();
		Linear attractionTimeConstraint = new Linear();
		Linear cultureDosageConstraint = new Linear();
		Linear extremeDosageConstraint = new Linear();
		Linear familyDosageConstraint = new Linear();
		Linear nightLifeDosageConstraint = new Linear();
		Linear trekkingDosageConstraint = new Linear();
		for (int i=0; i<cityAttractions.size(); i++) {
			Attraction attraction = cityAttractions.get(i);
			String attractionVarName = "a" + i;
			//define boolean for each attraction a1,a2...
			problem.setVarType(attractionVarName, VarType.BOOL);
			//build objective linear (a1*a1_e1 + a2*a2_e2 +....)	
			linearObjective.add(attraction.getEnjoymentLevel(), attractionVarName);
			//time constraint(a1*a1_t1 + a2*a2_t2 +... <= c_t)
			attractionTimeConstraint.add(attraction.getTime(), attractionVarName);
			if(attraction.getAttractionType() == AttractionType.CULTURE){
				cultureDosageConstraint.add(attraction.getTime(), attractionVarName);
			}
			else if(attraction.getAttractionType() == AttractionType.EXTREME){
				extremeDosageConstraint.add(attraction.getTime(), attractionVarName);
			}
			else if(attraction.getAttractionType() == AttractionType.FAMILY){
				familyDosageConstraint.add(attraction.getTime(), attractionVarName);
			}
			else if(attraction.getAttractionType() == AttractionType.NIGHT_LIFE){
				nightLifeDosageConstraint.add(attraction.getTime(), attractionVarName);
			}
			else{
				trekkingDosageConstraint.add(attraction.getTime(), attractionVarName);
			}
			
		}
		problem.setObjective(linearObjective, OptType.MAX);
		problem.add(attractionTimeConstraint, "<=", city.getTime());
		problem.add(cultureDosageConstraint, "<=", city.getTime()*desiredDosage.getCulturePercentage()/100);
		problem.add(extremeDosageConstraint, "<=", city.getTime()*desiredDosage.getExtremePercentage()/100);
		problem.add(familyDosageConstraint, "<=", city.getTime()*desiredDosage.getFamilyPercentage()/100);
		problem.add(nightLifeDosageConstraint, "<=", city.getTime()*desiredDosage.getNightLifePercentage()/100);
		problem.add(trekkingDosageConstraint, "<=", city.getTime()*desiredDosage.getTrekkingPercentage()/100);
		
		Solver solver = factory.get(); 
		Result result = solver.solve(problem);
		for (int i=0; i<cityAttractions.size(); i++){
			String attractionVarName = "a" + i;
			if(result.getPrimalValue(attractionVarName).intValue() == 1){
				resultAttractions.add(cityAttractions.get(i));
			}
		}
		System.out.println(result);

		return resultAttractions;
	}

}
